package com.onec.service.gateway.service.system;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.nimbusds.jose.JWSObject;
import com.onec.service.api.content.AuthConstants;
import com.onec.service.api.dto.request.RequestData;
import com.onec.service.api.dto.request.gateway.BizContent;
import com.onec.service.api.dto.response.ResponseData;
import com.onec.service.api.enums.ResultCodeEnum;
import com.onec.service.api.exception.GatewayException;
import org.apache.logging.log4j.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange;

import java.text.ParseException;
import java.util.Optional;

/**
 * app 鉴权，认证：
 *
 * @author onec
 * @see
 * @since 20201119
 */
@Service("APP")
public class AppSourceService extends DefaultBaseSourceServiceImpl {

    private static final Logger logger = LoggerFactory.getLogger(AppSourceService.class);

    /**
     * 数据加密和解密：同时验证token的有效性。
     *
     * @param requestData
     * @param exchange
     * @return
     */
    @Override
    public BizContent decryptRequestData(RequestData requestData, ServerWebExchange exchange) {

        String token = exchange.getRequest().getHeaders().getFirst(AuthConstants.JWT_TOKEN_HEADER);
        if (StrUtil.isEmpty(token)) {
            return decryptAgentNo(requestData);
        }
        token = token.replace(AuthConstants.JWT_TOKEN_PREFIX, Strings.EMPTY);
        JWSObject jwsObject = null;
        try {
            jwsObject = JWSObject.parse(token);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        // token 有误：
        if (Optional.ofNullable(jwsObject).isEmpty()) {
            throw new GatewayException(ResultCodeEnum.USER_ACCESS_LOCK);
        }
        // 验证token是否正确：
        jwsObject.getState();
        String payload = jwsObject.getPayload().toString();
        // 黑名单token(登出、修改密码)校验
        JSONObject jsonObject = JSONUtil.parseObj(payload);
        // JWT唯一标识
        String jti = jsonObject.getStr("jti");
        logger.info("gateway:token 验证");

        Boolean isBlack = redisTemplate.hasKey(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti);
        if (isBlack) {
            throw new GatewayException(ResultCodeEnum.USER_ACCESS_RETRY);
        }
        ServerHttpRequest request = exchange.getRequest().mutate()
                .header(AuthConstants.JWT_PAYLOAD_KEY, payload)
                .build();
        exchange.mutate().request(request).build();
        return decryptAgentNo(requestData);
    }

    @Override
    public ResponseData encryptResponseData(ResponseData responseData) {
        return encryptAgentNo(responseData);
    }
}
